package watchdog

import (
	"context"
	"log"
	"path/filepath"
	"time"

	"github.com/fsnotify/fsnotify"
)

// 文件事件处理方法
type WatchdogHandler func(op fsnotify.Op)

// 文件监控器
type watchdog struct {
	ctx      context.Context
	name     string
	watcher  *fsnotify.Watcher
	handlers map[string]WatchdogHandler
	lastTime time.Time
}

func NewWatchdog(ctx context.Context, name string) (*watchdog, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	return &watchdog{
		ctx:      ctx,
		name:     name,
		watcher:  watcher,
		handlers: make(map[string]WatchdogHandler, 10),
	}, nil
}

// 添加监控路径及事件处理逻辑 (如果出现了Remove行为,需要重新添加)
func (w *watchdog) AddPath(path string, handler WatchdogHandler) error {
	absPath, err := filepath.Abs(path)
	if err != nil {
		return err
	}
	if err = w.watcher.Add(absPath); err != nil {
		return err
	}
	w.handlers[absPath] = handler
	return nil
}

// 删除监控路径
func (w *watchdog) RemovePath(path string) error {
	absPath, err := filepath.Abs(path)
	if err != nil {
		return err
	}
	if err = w.watcher.Remove(absPath); err != nil {
		return err
	}
	delete(w.handlers, absPath)
	return nil
}

// 开始监控 (<100ms内的连续事件视为编辑器操作, 不触发handle)
func (w *watchdog) Start() {
	go func() {
		defer log.Printf("[watchdog]: %s Stopped", w.name)
		for {
			select {
			case event, ok := <-w.watcher.Events:
				if !ok {
					return
				}
				if time.Since(w.lastTime) >= 100*time.Millisecond {
					w.handle(event.Name, event.Op)
				}
			case err, ok := <-w.watcher.Errors:
				if !ok {
					return
				}
				log.Fatalf("[watchdog]: %s", err.Error())
			case <-w.ctx.Done():
				return
			}
		}
	}()
}

// 关闭监控
func (w *watchdog) Close() {
	w.watcher.Close()
}

func (w *watchdog) handle(path string, op fsnotify.Op) {
	w.lastTime = time.Now()
	w.handlers[path](op)
}
